#include "log.hpp"

class udpServer
{
private:
    uint16_t port_;
    string ip_;
    int sockfd_;
    unordered_map<string, struct sockaddr_in> users_; // ip:port peer
public:
    udpServer(int port, string ip = "")
        : port_((uint16_t)port), ip_(ip), sockfd_(-1)
    {
    }
    ~udpServer() {}

    void init()
    {
        // 1.创建socket，打开文件
        sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd_ < 0)
        {
            logMessage(FATAL, "socket : %s:%d", strerror(errno), sockfd_);
            exit(1);
        }
        // 2.绑定网络信息，指明ip和port
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        // 2.1填充协议家族，域
        local.sin_family = AF_INET;
        // 2.2填充服务器对应的端口号
        local.sin_port = htons(port_);
        // 2.3填充IP地址     //将点分十进制转化成四字节ip
        local.sin_addr.s_addr = ip_.empty() ? htonl(INADDR_ANY) : inet_addr(ip_.c_str());

        // 2.4绑定网络信息
        if (bind(sockfd_, (struct sockaddr *)&local, sizeof(local)) == -1)
        {
            logMessage(FATAL, "bind : %s:%d", strerror(errno), sockfd_);
        }
        cout << "create server success" << endl;
    }

    void start()
    {
        char inbuffer[1024];
        char outbuffer[1024];
        while (1)
        {
            // 往peer写入客户端信息
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            ssize_t s = recvfrom(sockfd_, inbuffer, sizeof(inbuffer) - 1,
                                 0, (struct sockaddr *)&peer, &len);
            if (s > 0)
            {
                inbuffer[s] = '\0';
            }
            else
            {
                logMessage(WARINING, "recvfrom : %s:%d", strerror(errno), sockfd_);
                continue;
            }
            // 取出客户端的ip和port
            string peerIp = inet_ntoa(peer.sin_addr);
            uint32_t peerPort = ntohs(peer.sin_port);
            logMessage(NOTICE, "[%s:%d]# %s", peerIp.c_str(), peerPort, inbuffer);
            broadcastMessage(peerIp, peerPort, peer, inbuffer); // 如果是新用户 就先添加用户
        }
    }

    void broadcastMessage(string peerIp, uint32_t peerPort, struct sockaddr_in peer, char *send)
    {
        string socket = peerIp + ":";
        socket += to_string(peerPort);
        auto it = users_.find(peerIp);
        if (it == users_.end())
            users_.insert({socket, peer});

        string message="FROM";
        message += "[";
        message += peerIp;
        message += ":";
        message += to_string(peerPort);
        message += "]";
        message += " echo# ";
        message += send;
        for (auto &user : users_)
        {
            if (user.first != socket)
            {
                sendto(sockfd_, message.c_str(), message.size(),
                       0, (struct sockaddr *)&user.second, sizeof(user.second));
            }
        }
    }
};

int main(int argc, char *argv[])
{
    using namespace std;
    if (argc != 2 && argc != 3)
    {
        cout << "Usage:\n\t " << argv[0] << " port [ip]" << endl;
        exit(3);
    }
    uint16_t port = atoi(argv[1]);
    string ip;
    if (argc == 3)
        ip = argv[2];
    udpServer svr(port, ip);
    svr.init();
    svr.start();
    return 0;
}